import os
import sys
import yaml
import pandas as pd
import numpy as np
import json
from tqdm import tqdm

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))

from src.data_prep.data_loader import load_software_data, process_software_features, split_train_test
from src.features.feature_engineer import SoftwareFeatureEngineer
from src.models.model_trainer import train_software_model


def generate_mock_software_data(num_samples: int = 1000) -> pd.DataFrame:
    """
    生成模拟软件数据用于演示
    """
    print(f"正在生成{num_samples}条模拟软件数据...")
    
    np.random.seed(42)
    data = []
    
    for i in tqdm(range(num_samples)):
        device_id = f"ESL-{np.random.randint(100, 300)}-{str(i).zfill(3)}"
        
        # 生成错误码分布
        error_code_dist = {
            'NET_TIMEOUT': np.random.randint(0, 50),
            'MEM_OVERFLOW': np.random.randint(0, 10),
            'IO_ERROR': np.random.randint(0, 20),
            'SENSOR_FAIL': np.random.randint(0, 15)
        }
        
        # 心跳间隔标准差
        heartbeat_interval_std = np.random.uniform(1.0, 10.0)
        
        # 异常重启次数
        reboot_count = np.random.randint(0, 10)
        
        # 网络重试占比
        network_retry_ratio = np.random.uniform(0.01, 0.8)
        
        # 日志熵
        log_entropy = np.random.uniform(1.0, 3.0)
        
        # 计算异常分数
        anomaly_score = (
            error_code_dist['NET_TIMEOUT'] / 50 * 0.3 +  # 网络超时是主要因素
            error_code_dist['MEM_OVERFLOW'] / 10 * 0.25 +  # 内存溢出风险高
            heartbeat_interval_std / 10 * 0.2 +  # 心跳不稳定
            reboot_count / 10 * 0.15 +  # 重启次数
            log_entropy / 3 * 0.1  # 日志混乱度
        )
        
        # 添加随机因素
        anomaly_score += np.random.normal(0, 0.05)
        
        # 决定是否发生软件故障（二分类标签）
        software_failure = 1 if anomaly_score > 0.6 else 0
        
        # 对于有故障的设备，增加错误数量和异常指标
        if software_failure == 1:
            # 增加网络超时错误
            error_code_dist['NET_TIMEOUT'] = max(error_code_dist['NET_TIMEOUT'], np.random.randint(15, 50))
            # 增加心跳间隔标准差
            heartbeat_interval_std = max(heartbeat_interval_std, np.random.uniform(5.0, 10.0))
            # 增加重启次数
            reboot_count = max(reboot_count, np.random.randint(3, 10))
        
        # 将error_code_dist转换为JSON字符串
        error_code_json = json.dumps(error_code_dist, ensure_ascii=False)
        
        data.append({
            'device_id': device_id,
            'error_code_dist': error_code_json,
            'heartbeat_interval_std': round(heartbeat_interval_std, 2),
            'reboot_count': reboot_count,
            'network_retry_ratio': round(network_retry_ratio, 3),
            'log_entropy': round(log_entropy, 2),
            'software_failure': software_failure
        })
    
    return pd.DataFrame(data)


def main():
    """
    主函数
    """
    # 加载配置
    config_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
                             'config', 'config.yaml')
    with open(config_path, 'r', encoding='utf-8') as f:
        config = yaml.safe_load(f)
    
    # 创建数据目录
    os.makedirs(config['data']['sample_data_path'], exist_ok=True)
    
    # 生成模拟数据
    software_data_path = os.path.join(config['data']['sample_data_path'], 'software_sample_data.csv')
    if not os.path.exists(software_data_path):
        df = generate_mock_software_data(2000)
        df.to_csv(software_data_path, index=False)
        print(f"模拟数据已保存至: {software_data_path}")
    else:
        print(f"使用已有的模拟数据: {software_data_path}")
        df = pd.read_csv(software_data_path)
    
    # 处理数据
    print("开始处理数据...")
    df = process_software_features(df)
    
    # 特征工程
    print("开始特征工程...")
    feature_engineer = SoftwareFeatureEngineer()
    df = feature_engineer.build_features(df)
    
    # 准备特征和标签
    exclude_cols = ['device_id', 'software_failure']
    feature_cols = [col for col in df.columns if col not in exclude_cols]
    
    X = df[feature_cols]
    y = df['software_failure']
    
    # 检查数据分布
    print(f"\n数据分布:")
    print(f"正常样本数: {(y == 0).sum()}")
    print(f"异常样本数: {(y == 1).sum()}")
    print(f"异常样本比例: {(y == 1).sum() / len(y):.2%}")
    
    # 划分训练集和测试集
    print("\n划分训练集和测试集...")
    X_train, X_test, y_train, y_test = split_train_test(X, y)
    
    print(f"训练集大小: {len(X_train)}, 测试集大小: {len(X_test)}")
    
    # 训练模型
    print("开始训练软件异常检测模型...")
    model = train_software_model(
        config=config,
        X_train=X_train,
        y_train=y_train,
        X_test=X_test,
        y_test=y_test
    )
    
    print("\n模型训练完成！")
    print(f"模型保存路径: {config['models']['software_model_path']}")


if __name__ == "__main__":
    main()
